#include "sse_str.h"
#include <stdlib.h>

typedef struct Header {
	unsigned int hash;
	unsigned int seed;
	size_t       len;
}Header;

typedef struct SseString {
	Header  header;
	char    data[1]; //for \0
}SseString;


sse_str_t sse_str_init_buffer_len(char* buf, size_t buf_len,
	const char* str, size_t str_len) {

	if (buf_len < sizeof(SseString) + str_len || !buf || !str) {
		return NULL;
	}
	SseString* ss = (SseString*)buf;
	ss->header.len = str_len;
	ss->header.hash = 0;
	ss->header.seed = 0;
	memcpy(ss->data, str, str_len);
	ss->data[str_len] = '\0';
	return ss->data;
}

sse_str_t sse_str_init_buffer(char* buf, size_t buf_len,
	const char* str) {
	if (!str)
		return NULL;
	return sse_str_init_buffer_len(buf, buf_len, str, strlen(str));
}

sse_str_t sse_str_new_len(const char* str, size_t len) {
	if (!str) {
		return NULL;
	}
	SseString* ss = malloc(sizeof(SseString) + len);
	if (ss) {
		ss->header.len = len;
		ss->header.hash = 0;
		ss->header.seed = 0;
		memcpy(ss->data, str, len);
		ss->data[len] = '\0';
	}
	return ss->data;
}

sse_str_t sse_str_new(const char* str) {
	if (!str) {
		return NULL;
	}
	return sse_str_new_len(str, strlen(str));
}

void sse_str_free(sse_str_t str) {
	if (!str) {
		return;
	}
	SseString* ss =(SseString*)(str - sizeof(Header));
	free(ss);
}

size_t  sse_str_len(sse_str_t str) {
	if (!str)
		return 0;
	SseString* ss = (SseString*)(str - sizeof(Header));
	return ss->header.len;
}

unsigned int sse_str_hash(sse_str_t str, unsigned int seed) {
	if (!str)
		return 0;
	SseString* ss = (SseString*)(str - sizeof(Header));
	if (ss->header.seed == seed) {
		return ss->header.hash;
	}
	ss->header.seed = seed;
	ss->header.hash = sse_hash(str, seed);
	return ss->header.hash;
}

unsigned int sse_hash(const char* s, unsigned int hash) {
	if (!s || !hash)
		return 0;

	for (; *s; ++s) {
		hash += (hash << 1) + (hash << 4) + (hash << 7) +
			(hash << 8) + (hash << 24);

		hash ^= (*s == '-' ? '_' : *s);
	}
	return hash & 0xfffffff;
}


